package main

import (
	"github.com/ngaut/log"
	"encoding/json"
	"global/function"
	"global/structs"
	"strings"
	"github.com/shopspring/decimal"
	"github.com/garyburd/redigo/redis"
	"server/order/model"
)

type AnalysisResult struct {
	Max  		string              `json:"max"`
	Min  		string              `json:"min"`
	Sum  		string              `json:"sum"`
	LastPrice 	string 			 	`json:"last"`
	PrePrice 	string				`json:"pre"`
}

type Order struct {
	ctx 		*Context
}

func NewOrder(ctx *Context) *Order {
	return &Order{
		ctx: 	ctx,
	}
}

func (self *Order) run()  {
	conn := self.ctx.GetOteRedis().Get()
	if conn == nil {
		log.Error("get redis pool failed")
		return
	}
	defer conn.Close()

	lastOrderId := getLastOrderId(conn)
	log.Infof("get last order id: %d", lastOrderId)

	orders := model.OrderCoinModel.GetOrderCoins(lastOrderId)
	if orders == nil || len(orders) == 0 {
		return
	}

	log.Debugf("query order list length: %d", len(orders))

	newLastId := orders[len(orders) - 1].Id
	log.Infof("save new last order id: %d", newLastId)

	setLastOrderId(conn, newLastId)

	var tmp = make(map[string][]structs.OrderCoin)
	for _, order := range orders {
		coin := order.CoinFrom + "_" + order.CoinTo
		if _, exists := tmp[coin]; !exists {
			tmp[coin] = make([]structs.OrderCoin, 0)
		}
		tmp[coin] = append(tmp[coin], order)
	}

	self.handlerOrders(tmp)
}

func (self *Order) handlerOrders(orders map[string][]structs.OrderCoin) {
	for coin, orderCoins := range orders {
		self.handlerOrder(coin, orderCoins)
	}
}

func (self *Order) handlerOrder(coinPair string, orders []structs.OrderCoin) {
	conn := self.ctx.GetOteRedis().Get()
	if conn == nil {
		log.Error("get ote redis pool failed")
		return
	}

	defer conn.Close()

	coins := strings.Split(coinPair, "_")
	if len(coins) != 2 {
		return
	}

	result := getAnalysisResults(conn, coinPair)
	var orderLength = len(orders)
	var last, prev decimal.Decimal
	var max, min, sum decimal.Decimal

	// last
	last, _ = decimal.NewFromString(orders[orderLength-1].Price)

	// pre
	if orderLength >= 2 {
		prev, _ = decimal.NewFromString(orders[orderLength-2].Price)
	} else {
		if result != nil {
			prev, _ = decimal.NewFromString(result.LastPrice)
		} else {
			prev = decimal.Zero
		}
	}

	stats := model.OrderCoinModel.GetMinMaxSum(coins[0], coins[1])
	if stats != nil {
		max, _ = decimal.NewFromString(string(stats["max"]))
		min, _ = decimal.NewFromString(string(stats["min"]))
		sum, _ = decimal.NewFromString(string(stats["s"]))
	}

	analysis := AnalysisResult{
		Max: 		max.StringFixedBank(8),
		Min: 		min.StringFixedBank(8),
		Sum: 		sum.StringFixedBank(8),
		LastPrice: 	last.StringFixedBank(8),
		PrePrice: 	prev.StringFixedBank(8),
	}

	setAnalysisResults(conn, coinPair, analysis)
	log.Infof("set analysis success, max: %s, min: %s, sum: %s, last: %s, pre: %s",
		analysis.Max, analysis.Min, analysis.Sum, analysis.LastPrice, analysis.PrePrice)

}

func setAnalysisResults(conn redis.Conn, coinPair string, result AnalysisResult) {
	marshalResult, err := json.Marshal(result)
	if err != nil {
		log.Errorf("json marshal analysis result error, msg: %s", err.Error())
		return
	}

	_, err = conn.Do("SET", function.GetOrderLatestAnalysisKey(coinPair), string(marshalResult))
	if err != nil {
		log.Errorf("cache analysis data error, msg: %s", err)
	}
}

func getAnalysisResults(conn redis.Conn, coinPair string) *AnalysisResult {
	key := function.GetOrderLatestAnalysisKey(coinPair)
	detail, err := redis.String(conn.Do("GET", key))
	var result AnalysisResult
	if err != nil {
		log.Errorf("get analysis result error, key: %s, msg: %s", key, err.Error())
		return nil
	}
	err = json.Unmarshal([]byte(detail), &result)
	if err != nil {
		log.Errorf("json unmarshal order analysis result error, err: %s", err.Error())
		return nil
	}
	return &result
}

func getLastOrderId(conn redis.Conn) int {
	lastId, err := redis.Int(conn.Do("GET", function.GetOrderLastIdKey()))
	if err != nil {
		log.Errorf("get last id error, msg: %s", err.Error())
		c := model.OrderCoinModel.GetCount()
		if c < 1000 {
			return 0
		}
		return c - 1000
	}
	return lastId
}

func setLastOrderId(conn redis.Conn, id int) {
	_, err := conn.Do("SET", function.GetOrderLastIdKey(), id)
	if err != nil {
		log.Errorf("save last order error, msg: %s", err.Error())
	}
}